package com.tengyun.middleplatform.trade.tradedata.util;

import com.alibaba.fastjson.JSON;
import com.tengyun.middleplatform.trade.tradedata.config.AikeProperties;
import com.tengyun.wii.request.WiiRequest;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.message.BasicHeader;
import org.linuxprobe.luava.http.HttpRequestUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.security.MessageDigest;
import java.util.*;

/**
 * @Author: likailun
 * @Description:
 * @Date: create in 2022/8/25 11:16 AM
 */
@Slf4j
@Component
public class AikeHttpUtil {
    @Resource
    private WiiRequest wiiRequest;
    @Resource
    private AikeProperties properties;

    private Map<String,String> auth=new HashMap<>();
    private static  final char HEX_DIGITS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E', 'F' };

    public AikeResponse postJson(String url, Map<String,Object> params){
        CloseableHttpResponse response = wiiRequest.getHttpRequestUtils().httpRequest("POST", properties.getHost()+url, null, params, false,getHeader(params));
        final AikeResponse aikeResponse = HttpRequestUtils.responseDataSnakeConversion(response, AikeResponse.class);
        return aikeResponse;
    }

    private String getAikeToken(){
        final Optional<String> aikeAuthToken = CacheUtils.getAikeAuthToken();
        if(aikeAuthToken.isPresent()){
            return aikeAuthToken.get();
        }
        Map<String, String> params = new HashMap<>();
        params.put("app_id",properties.getAppId());
        params.put("app_key",properties.getAppKey());
        //类型：1：请求token
        params.put("type","1");
        params.put("timestamp", String.valueOf(Calendar.getInstance().getTimeInMillis()/1000));
        final StringBuffer sb = new StringBuffer();
        sb.append(params.get("app_key")).append("%%").append(params.get("type")).append("%%").append(properties.getAppSecret()).append("%%").append(params.get("timestamp"));
        params.put("signature",MD5(sb.toString()));
        CloseableHttpResponse response = wiiRequest.getHttpRequestUtils().httpRequest("POST", properties.getHost()+"/api/wechat/Token/GetAccessCode", null, params, false, (Header) null);
        final AikeResponse aikeResponse = HttpRequestUtils.responseDataSnakeConversion(response, AikeResponse.class);
        if(aikeResponse!=null && aikeResponse.getResultCode().equals("100") && aikeResponse.getResultObject()!=null){
            final LinkedHashMap<String,String> resultObject = (LinkedHashMap<String, String>) aikeResponse.getResultObject();
            final String accessCode = MapUtils.getString(resultObject,"access_code");
            Map<String, String> tokenPrams = new HashMap<>();
            tokenPrams.put("app_id",properties.getAppId());
            tokenPrams.put("app_key",properties.getAppKey());
            tokenPrams.put("code",accessCode);
            tokenPrams.put("timestamp", String.valueOf(Calendar.getInstance().getTimeInMillis()/1000));
            final StringBuffer sbt = new StringBuffer();
            sbt.append(tokenPrams.get("app_key")).append("%%").append(tokenPrams.get("code")).append("%%").append(properties.getAppSecret()).append("%%").append(tokenPrams.get("timestamp"));
            tokenPrams.put("signature",MD5(sbt.toString()));
            CloseableHttpResponse tokenResponse = wiiRequest.getHttpRequestUtils().httpRequest("POST", properties.getHost()+"/api/wechat/Token/GetAccessToken", null, tokenPrams, false, (Header) null);
            final AikeResponse aikeTokenResponse = HttpRequestUtils.responseDataSnakeConversion(tokenResponse, AikeResponse.class);
            if(aikeTokenResponse!=null && aikeTokenResponse.getResultCode().equals("100") && aikeTokenResponse.getResultObject()!=null){
                final LinkedHashMap<String,String> tokenObject = (LinkedHashMap<String, String>) aikeTokenResponse.getResultObject();
                final String accessToken = MapUtils.getString(tokenObject, "access_token");
                final Integer expiresIn = MapUtils.getInteger(tokenObject, "expires_in");
                // 提前5分钟过期
                final long expiresSecond = expiresIn-Calendar.getInstance().getTimeInMillis() / 1000 - 300;
                log.info("access_token:{},expires_in:{},缓存时间：{}",accessToken,expiresIn,expiresSecond);
                //CacheUtils.setAikeAuthToken(accessToken,expiresSecond);
                return accessToken;
            }
        }
        return "";
    }

    private Header[] getHeader(Map<String,Object> params){
        final StringBuilder sb = new StringBuilder();
        final long time = Calendar.getInstance().getTimeInMillis() / 1000;
        sb.append(JSON.toJSONString(params)).append(time).append(properties.getAppSecret());
        return new Header[]{
                new BasicHeader("accessToken", getAikeToken()),
                new BasicHeader("timestamp", String.valueOf(time)),
                new BasicHeader("signature", MD5(sb.toString()))
        };
    }
    private  String MD5(String s) {
        try {
            byte[] btInput = s.getBytes();
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();
            // 把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = HEX_DIGITS[byte0 >>> 4 & 0xf];
                str[k++] = HEX_DIGITS[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    @Data
    public static class AikeResponse{
        private String resultMsg;
        private String resultCode;
        private Object resultObject;
    }
}
